///////////////////////////////////////////////////////////////////////////////////////////////////
// Illusion Ray Development Kit (IDK)           Copyright (c) 2010 ( dimitriy.martynenko@gmail.com )
///////////////////////////////////////////////////////////////////////////////////////////////////
// Created : 2010-05-22
// Updated : ...
// Licence : NEW BSD
// Info	   : IDK Engine
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include <System.hpp>

namespace IDK
{
	//
	// FORWARD DECLARATION
	//
	//
	// Implementation
	//
	//
	//
	//
	/*-------------------------------------------------------------------------
	| IModule:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IModule : virtual public IObject
	{
		virtual void OnInit(void) = 0;
		virtual void OnStart(void) = 0;
		virtual void OnUpdate(float dt) = 0;
		virtual void OnActive(bool active) = 0;
		virtual void OnFinish(void) = 0;
		virtual void Lock(bool reset) = 0;
		virtual void Unlock(void) = 0;
	};

	/*-------------------------------------------------------------------------
	| IStream:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IStream : virtual public IObject
	{
		virtual bool IsCanRead() = 0;
		virtual String GetPath(void) const = 0;
		virtual bool IsOpen(void) const = 0;
		virtual void Open(bool create = false) = 0;
		virtual void Close(void) = 0;
		virtual uint GetSize(void) = 0;
		virtual uint GetPos(void) = 0;
		virtual void SetPos(uint pos) = 0;
		virtual uint Seek(uint pos) = 0;
		virtual String ReadString(void) = 0;
		virtual String ReadText(void) = 0;
		virtual void ReadMemory(UnSafePtr ptr, uint size) = 0;

		template<class T>
		T Read()
		{
			T val;
			ReadMemory(&val, sizeof(val));
			return val;
		}

		void ReadData(HandlePtr data, uint size, uint offset = 0)
		{
			ReadMemory((UnSafePtr)((uint)data->GetPointer()+offset), size);
		}

		template<class T>
		void ReadData(T& obj)
		{
			ReadData(new THandleBindPtr<T*>(&obj), sizeof(T));
		}


		template<typename T>
		void ReadData(DynamicArray<T> dynArr, uint size, uint offset = 0)
		{
			ReadData(dynArr.template As<THandlePtr> (), size, offset);
		}
	};

	typedef ref<IStream> Stream;

	/*-------------------------------------------------------------------------
	| IFileSystem:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IFileSystem : virtual public IObject
	{
		virtual void Initialize(const String path) = 0;
		virtual ref<IStream> GetStream(const String ref) = 0;
	};

	/*-------------------------------------------------------------------------
	| IResource:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IResource : virtual public IObject 
	{
		struct LoadStatus
		{
			enum Enum
			{
				Wait = 0,
				Loading,
				Loaded,
				Ready,
				Cancel
			};
		};

		enum LoadPriority
		{
			VeryLowPriority = 0,
			LowPriority,
			NormalPriority = 127,
			HighPriority,
			VerHighPriority = 255
		};

		virtual ref<IStream> GetResourceStream(void) = 0;
		virtual uint GetLoadPriority(void) = 0;
		virtual LoadStatus::Enum GetLoadStatus(void) = 0;
		virtual void SetLoadStatus(LoadStatus::Enum  status) = 0;
		virtual void OnLoad(float dt) = 0;
		virtual void Cleanup(void) = 0;
	};

	/*-------------------------------------------------------------------------
	| IOcclusionQuery:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IOcclusionQuery: virtual public IObject
	{
		virtual void Update(const Math::Matrix44& proj, const Math::Matrix44& view) = 0;
		virtual void Enable(bool value) = 0;
		virtual bool AABBInSpace(const Math::AABB& aabb, float& distance) const = 0;
		virtual float GetNearDistance(const Math::AABB& aabb) const = 0;
	};

	/*-------------------------------------------------------------------------
	| Pixel:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct Pixel
	{
		struct Type
		{
			enum Enum
			{
				RGBA4 = 0,
				RGBA8,
				RGB_DXT1,
				RGBA_DXT1,
				RGBA_DXT3,
				RGBA_DXT5,
				RGBA_PVR2,
				RGBA_PVR4,
				MAX
			};
		};

		struct Filter
		{
			enum Enum
			{
				None,
				Point,
				MipMap
			};
		};
	};

	/*-------------------------------------------------------------------------
	| GPUResource:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPUResource :  virtual public IObject
	{
		virtual bool IsInvalid() = 0;
		virtual void Dispose() = 0;
	};

	typedef ref<IGPUResource> GPUResource;

	/*-------------------------------------------------------------------------
	| GPUTexture:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPUTexture :  virtual public IGPUResource
	{
		virtual void Bind(uint index) = 0;
		virtual void Update(uint level, uint w, uint h, HandlePtr data, uint size) = 0;
		virtual void Unbind(uint index) = 0;
	};
	typedef ref<IGPUTexture> GPUTexture;

	/*-------------------------------------------------------------------------
	| GPUTexture:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPURenderTexture :  virtual public IGPUTexture
	{
		virtual void Attach(uint index) = 0;
	};

	typedef ref<IGPURenderTexture> GPURenderTexture;
	/*-------------------------------------------------------------------------
	| GPUTexture:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPUShader : virtual public IGPUResource
	{
		virtual void Bind() = 0;
		virtual void Unbind() = 0;
	};
	typedef ref<IGPUShader> GPUShader;

	/*-------------------------------------------------------------------------
	| GPUTexture:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPURenderTarget :  virtual public IGPUResource
	{
		virtual void Bind() = 0;
		virtual void Unbind() = 0;
	};
	typedef ref<IGPURenderTarget> GPURenderTarget;

	/*-------------------------------------------------------------------------
	| GPUVertexBinding:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct GPUVertexBinding
	{
		struct Type
		{
			enum Enum
			{
				Position,
				Normal,
				Tangent,
				UV0,
				MAX
			};
		};

		uint bind[Type::MAX];
	};
	/*-------------------------------------------------------------------------
	| GPUIndexBuffer:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPUIndexBuffer :  virtual public IGPUResource
	{
		virtual void Bind() = 0;
		virtual void Unbind() = 0;
	};
	typedef ref<IGPUIndexBuffer> GPUIndexBuffer;

	/*-------------------------------------------------------------------------
	| GPUVertexBuffer:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IGPUVertexBuffer :  virtual public IGPUResource
	{
		virtual void Bind(const GPUVertexBinding& binding) = 0;
		virtual void Unbind(const GPUVertexBinding& binding) = 0;
	};
	typedef ref<IGPUVertexBuffer> GPUVertexBuffer;

	
	/*-------------------------------------------------------------------------
	| IShaderParameter:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IShaderParameter : virtual public IHandleID<>, virtual public INameable
	{
		struct Declaration
		{	
			enum Enum
			{
				None = 0,
				VertexPosition = GPUVertexBinding::Type::Position,
				VertexNormal = GPUVertexBinding::Type::Normal,
				VertexTangent = GPUVertexBinding::Type::Tangent,
				VertexTexUV0 = GPUVertexBinding::Type::UV0,
				MatrixProjection,
				MatrixView,
				MatrixWorld,
				MatrixViewInverse,
				Texture0,
				Texture1,
				Texture2,
				Texture3,
				Texture4,
				Constant2f,
				Constant3f,
				Constant4f,
				Constant44f,
				TimeFrame,
				TimeElapsed,
				MAX
			};
		};

		struct Type
		{
			enum Enum
			{
				VertexAttribute = 0,
				ConstantParameter
			};
		};

		virtual Declaration::Enum GetDeclaration(void) = 0;
		virtual Type::Enum GetType(void) = 0;
		virtual HandlePtr GetCustomData(void) = 0;
	};

	typedef ref<IShaderParameter> ShaderParameter;
	typedef Array<ShaderParameter> ShaderParameters;

	/*-------------------------------------------------------------------------
	| IRenderState:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IRenderState : virtual public IObject
	{
		struct DepthTest
		{ 
			enum Enum
			{
				//cull face
				None = 0,
				LessEqual,
				MAX
			};
		};

		struct CullFace 
		{ 
			enum Enum
			{
				//cull face
				None = 0,
				Front,
				Back,
				MAX
			};
		};

		struct Blend 
		{ 
			enum Enum
			{
				None = 0,
				AlphaBlend,
				MAX
			};
		};

		struct PrimitiveType
		{
			enum Enum
			{
				Lines = 0,
				TrinagleList,
				MAX,
			};
		};

		struct MatrixType
		{
			enum Enum
			{
				World,
				View,
				Projection,
				MAX,
			};
		};

		struct TextureBinding
		{
			enum Enum
			{
				MAX = 8,
			};
		};

		virtual GPUTexture CreateTexture(IDK::Pixel::Type::Enum type, IDK::Pixel::Filter::Enum filter) = 0;
		virtual void SetTexture(GPUTexture texture, uint index) = 0;

		virtual GPURenderTexture CreateRenderTexture(uint width, uint height, 
			Pixel::Type::Enum pixelType,
			Pixel::Filter::Enum filter) = 0;
		virtual void SetRenderTexture(GPURenderTexture texture, uint index) = 0;

		virtual GPUShader CreateShader(Stream vertStream, Stream fragStream, ShaderParameters parameters) = 0;
		virtual void SetShader(GPUShader shader) = 0;
		virtual void SetShaderParameters(IDK::ShaderParameters parameters) = 0;

		virtual GPURenderTarget CreateRenderTarget(uint width, uint heigth) = 0;
		virtual void SetRenderTarget(GPURenderTarget rtt) = 0;
		//virtual void SetIndexBuffer(IndexBuffer indexBuffer) = 0;
		//virtual void SetVertexBuffer(VertexBuffer vertexBuffer) = 0;
		virtual void SetMatrix(MatrixType::Enum type, const Math::Matrix44& m) = 0;

		virtual GPUIndexBuffer CreateIndexBuffer(uint indexSize, uint count, HandlePtr data) = 0;
		virtual GPUVertexBuffer CreateVertexBuffer(uint vertexSize, uint count, HandlePtr data) = 0;
		virtual void SetIndexBuffer(GPUIndexBuffer buffer) = 0;
		virtual void SetVertexBuffer(GPUVertexBuffer buffer) = 0;

		virtual void DrawIndexVertexData(PrimitiveType::Enum type, uint count) = 0;

		//simple
		virtual void DrawRect(const Math::Rect& rect = Math::Rect::Identity, const Math::Rect& trect = Math::Rect::Identity, float z = 0.0f) = 0;
		virtual void DrawLine(const Math::Vector3& start,const Math::Vector3& end) = 0;
		//gpu buffers
		virtual void Reset() = 0;

		//render state
		virtual void SetCullFace(CullFace::Enum mode) = 0;
		virtual void SetDepthTest(DepthTest::Enum mode) = 0;
		// occlusion query
		virtual ref<IOcclusionQuery> GetOcclusionQuery(void) = 0;

		virtual void SetBlend(Blend::Enum blend) = 0;

		virtual void ClearBuffers() = 0;
	};

	typedef ref<IRenderState> RenderState;

	/*-------------------------------------------------------------------------
	| IViewport:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IViewport : virtual public IObject
	{
		virtual uint GetWidth(void) const = 0;
		virtual uint GetHeight(void) const = 0;
		virtual HandlePtr GetDC(void) const = 0;
		virtual HandlePtr GetHWND(void) const = 0;
	};

	typedef ref<IViewport> Viewport;

	/*-------------------------------------------------------------------------
	| IRenderable:
	| ------------
	| *Renderable composition
	|---------------------------------------------------------------------------*/
	struct IRenderable : virtual public IObject
	{
		virtual bool Render(IRenderState& rndState) = 0;
		virtual void Rendered(IRenderState& rndState) = 0;
	};

	typedef ref<IRenderable> Renderable;

	/*-------------------------------------------------------------------------
	| IRenderer:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IRenderer : virtual public IModule
	{
		//
		struct IPass : virtual public IRenderable
		{
			//
		};

		virtual void AddPass(ref<IPass> pass) = 0;
		virtual void ClearPasses(void) = 0;

		virtual ref<IViewport> GetViewport(void) = 0;
		virtual void SetViewport(ref<IViewport> viewport) = 0;
	};

	/*-------------------------------------------------------------------------
	| ICamera:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct ICamera : virtual public IRenderable
	{
		struct MatrixMode
		{
			enum Enum
			{
				None = 0,
				View,
				Projection,
				MAX
			};
		};
		virtual void LookAt(const Math::Vector3& target) = 0;
		virtual void Update(float dt) = 0;
		virtual const Math::Matrix44& GetMatrix(MatrixMode::Enum mode) = 0;
		virtual const Math::Vector3& GetPosition(void) const = 0;
		virtual void SetPosition(const Math::Vector3& pos) = 0;
		virtual void Rotate(float x, float y) = 0;
		virtual const Math::Vector3 ScreenToWorld(const Math::Vector2& posXY) const = 0;
		virtual const Math::Vector3 ScreenToVector(const Math::Vector2& posXY) const = 0;
		virtual const Math::Vector3 GetAbsolutePosition(void) const = 0;
	};

	/*-------------------------------------------------------------------------
	| ITexture:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct ITexture : virtual public IObject
	{
		static const uint MaxMipCount = 6;

		virtual uint GetWidth(void) = 0;
		virtual uint GetHeight(void) = 0;
		virtual Pixel::Type::Enum GetPixelType(void) = 0;
		//
		virtual uint GetMipCount(void) = 0;
		virtual void BindTexture(IRenderState& rndState, uint index) = 0;
		virtual Pixel::Filter::Enum GetFilter(void) const = 0;
	};
	typedef ref<ITexture> Texture;

	/*-------------------------------------------------------------------------
	| IShader:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IShader : virtual public IRenderable
	{
		struct ProgramType
		{
			enum Enum
			{
				Vertex,
				Fragment,
				MAX
			};
		};

		virtual void AddParameter(IShaderParameter::Type::Enum typ, IShaderParameter::Declaration::Enum decl, const String& name, HandlePtr handleData = NullPtr) = 0;
		virtual void SetShaderSource(ProgramType::Enum typ, ref<IStream> stream) = 0;
		virtual Stream GetShaderSource(ProgramType::Enum typ) = 0;
		virtual ShaderParameters GetParameters(void) = 0;
	};

	typedef ref<IShader> Shader;

	/*-------------------------------------------------------------------------
	| IMaterial:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IMaterial : virtual public IRenderable, virtual public INameable
	{
		struct TextureMode
		{
			enum Enum
			{
				Sampler0 = 0,
				Sampler1,
				Sampler2,
				Sampler3,
				Sampler4,
				Sampler5,
				MAX
			};
		};

		virtual void SetTexture(TextureMode::Enum mode, ref<ITexture> tex) = 0;
		virtual void SetShader(ref<IShader> shader) = 0;
		virtual void SetBlendMode(IDK::IRenderState::Blend::Enum mode) = 0;
	};

	typedef ref<IMaterial> Material;

	/*-------------------------------------------------------------------------
	| IMesh:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IMesh : virtual public IRenderable
	{
	};

	typedef ref<IMesh> Mesh;


	/*-------------------------------------------------------------------------
	| ISceneModel:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct ISceneModel : virtual public IRenderable, virtual public INameable
	{
		virtual void SetMesh(ref<IMesh> mesh) = 0;
		virtual void SetMaterial(ref<IMaterial> material) = 0;
	};

	/*-------------------------------------------------------------------------
	| IRenderTexture:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IRenderTexture : virtual public ITexture
	{
		virtual void Attach(IRenderState& rndState, uint index) = 0;
	};

	typedef ref<IRenderTexture> RenderTexture;

	/*-------------------------------------------------------------------------
	| IRenderTarget:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct IRenderTarget : virtual public IRenderable
	{
		typedef Array<ref<IRenderTexture> > RenderTextures;

		virtual RenderTextures	GetRenderTextures(void) = 0;
		virtual ref<IRenderTexture> GetDepthTexture(void) = 0;
		virtual void			AttachTexture(ref<IRenderTexture> rndTex) = 0;
		virtual void			AttachDepth(ref<IRenderTexture> depthTex) = 0;
	};
	typedef ref<IRenderTarget> RenderTarget;

	/*-------------------------------------------------------------------------
	| ICore:
	| ------------
	| 
	|---------------------------------------------------------------------------*/
	struct ICore : virtual public IModule
	{
		virtual void							SetDefaultResourcePath(const String& path) = 0;
		virtual ref<IMesh>						GetMesh(const String& path) = 0;
		virtual ref<ITexture>					AddTexture(const String& path, Pixel::Type::Enum pixelType, uint mipCount, uint width, uint height) = 0;
		virtual ref<IMaterial>					GetMaterial(const String& name) = 0;
		virtual ref<IShader>				GetShader(const String& path) = 0;
		virtual ref<IRenderTarget>				GetRenderTarget(const String& name) = 0;
		//create block
		virtual ref<IRenderTexture>				CreateRenderTexture(uint width, uint height, Pixel::Type::Enum pixelType) = 0;
		virtual void							Clear(void) = 0;
		virtual Stream							GetStream(String path) = 0;
	};
	typedef ref<ICore> Core;
}
